<?php
namespace App\Models\AuthManage;

use App\Facades\ScarecrowAuth;
use App\Facades\ScarecrowDoLog;
use App\Models\User;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\DB;

class LoginModel {
	//用户密码盐值
	protected static $key = "ScarecrowAuthKey";

	//用户Cache缓存KEY前缀
	protected static $cachePrefix = "SUT_USER_INFO_";

	//缓存失效时间 S
	protected static $expireTime = 14400;

	//默认API调用次数
	public static $callNum = 5000;

	//当前用户菜单
	protected static $userMenu = [];

	/**
	 * 加密用户密码
	 * @param $userPassword
	 * @return string
	 */
	public static function CryptPassword($userPassword) {
		return md5(self::$key . $userPassword . self::$key);
	}

	/**
	 * 登录用户
	 * @param $userName
	 * @param $userPassword
	 * @return array
	 * @throws \Exception
	 */
	public static function LoginUser($userName, $userPassword) {
		$userObj =DB::table('sc_user')->where(['username'=>$userName, 'state'=>1])->first();
		if (!$userObj) {
			return ModelReturn(-1, '用户被停用或用户名密码错误');
		}
		$userObj = (array)$userObj;
		$checkPassword = self::CryptPassword($userPassword);

		if ($checkPassword !== $userObj['password']) {
			return ModelReturn(-1, '用户名或密码错误');
		}

		$tokenInfo = CreateToken($userObj['id']);
		$cacheToken = self::$cachePrefix . $tokenInfo['token'];
		unset($userObj['password']);

		$expireTime = time() + self::$expireTime;
		$cacheData = [
			'uid'	=>	$userObj['id'],
			'token'	=>	$tokenInfo['token'],
			'expire_time'	=>	$expireTime,
			'update_time'	=>	time(),
			'call_num'		=>	self::$callNum,
			'is_invalid'	=>	0
		];

		$userObj['tokenInfo'] = $cacheData;
		//如果需要路由权限，则在此处进行绑定
		$userObj['authList'] = self::getUserAuthList($userObj['id']);
		try {
			Cache::put($cacheToken, $userObj, self::$expireTime);
			DB::table('sc_token_cache')->insert($cacheData);
			HandleLog()->addLog('u', ['username'=>$userName], '登录了系统', $cacheData['token']);
			$cacheData['token'] = $tokenInfo['cryptToken'];
			return ModelReturn(0, '登录成功', $cacheData);
		} catch (\Throwable $e) {
			if (config('app.debug')) {
				return ModelReturn(1, $e->getMessage());
			} else {
				return ModelReturn(1, "登录失败");
			}
		}
	}

	/**
	 * 获取用户路由权限列表
	 * @param $uid
	 * @return array
	 */
	protected static function getUserAuthList($uid) {
		$allApiRouteList = DB::table('sc_system_role_user as t1')->leftJoin('sc_system_role as t2', 't1.role_id', '=', 't2.id')->leftJoin('sc_system_role_authority as t3', 't1.role_id', '=', 't3.role_id')->leftJoin('sc_system_authority as t4', 't4.id', '=', 't3.authority_id')->leftJoin('sc_system_authority_menu as t5', 't5.authority_id','=', 't4.id')->leftJoin('sc_system_api as t6', 't6.menu_id', '=', 't5.menu_id')->leftJoin('sc_system_menu as t7', 't7.id', '=', 't5.menu_id')->whereRaw("t2.status=1 AND t4.status=1 AND t7.status=1 AND t1.user_id=?", [$uid])->pluck('t6.url')->toArray();
		array_walk($allApiRouteList, function (&$api) {
			$api = trim($api, '/');
		});
		return $allApiRouteList;
	}

	/**
	 * 获取用户信息
	 * @param $token
	 * @param $key
	 * @param string $default
	 * @param bool $msutDb
	 * @return array获取用户信息
	 */
	public static function getUserInfo($token, $key='', $default="", $msutDb=false) {
		$cacheToken = self::$cachePrefix . $token;
		if (!$msutDb && Cache::has($cacheToken)) {
			$userInfo = Cache::get($cacheToken);
			if ($userInfo) {
				if ($key) {
					$keyList = explode('.', $key);
					$keyList = array_filter($keyList);
					$tempData = $userInfo;
					foreach ($keyList as $item) {
						if(isset($tempData[$item])) {
							$tempData = $tempData[$item];
						} else {
							return ModelReturn(0, '获取成功', $default);
						}
					}
					return ModelReturn(0, '获取成功', $tempData);
				} else {
					return ModelReturn(0, '获取成功', $userInfo);
				}
			}
		}

		$nowTime = time();
		$userObj = DB::table('sc_token_cache as t1')->leftJoin('sc_user as t2', 't2.id', '=', 't1.uid')->whereRaw("t1.expire_time>{$nowTime} AND t1.call_num>0 AND t1.token=? AND is_invalid=0", [$token])->select(['t2.*','t1.uid','t1.token','t1.expire_time','t1.update_time','t1.call_num', 't1.is_invalid'])->first();
		if (!$userObj) {
			return ModelReturn(1, '用户不存在');
		}
		$userObj = (array)$userObj;
		unset($userObj['password']);

		$tokenInfo = [
			'uid'	=>	$userObj['uid'],
			'token'	=>	$userObj['token'],
			'expire_time'	=>	$userObj['expire_time'],
			'update_time'	=>	time(),
			'call_num'		=>	$userObj['call_num'],
			'is_invalid'	=>	$userObj['is_invalid']
		];

		$userObj['tokenInfo'] = $tokenInfo;
		//如果需要路由权限，则在此处进行绑定
		$userObj['authList'] = self::getUserAuthList($userObj['id']);
		Cache::put($cacheToken, $userObj, self::$expireTime);

		$userInfo = $userObj;
		if ($userInfo) {
			if ($key) {
				$keyList = explode('.', $key);
				$keyList = array_filter($keyList);
				$tempData = $userInfo;
				foreach ($keyList as $item) {
					if(isset($tempData[$item])) {
						$tempData = $tempData[$item];
					} else {
						return ModelReturn(0, '获取成功', $default);
					}
				}
				return ModelReturn(0, '获取成功', $tempData);
			}
		}

		return ModelReturn(0, '获取成功', $userObj);
	}

	/**
	 * 更新token
	 * @param $token
	 * @return array
	 * @throws \Exception
	 */
	public static function updateToken($token) {
		$userInfo = self::getUserInfo($token);
		if ($userInfo['code'] != 0) {
			return ModelReturn(1,  $userInfo['msg']);
		}

		$userObj = $userInfo['data'];
		$newTokenInfo = CreateToken($userObj['id']);
		$expireTime = time() + self::$expireTime;
		$updateTokenInfo = [
			'token'	=>	$newTokenInfo['token'],
			'expire_time'	=>	$expireTime,
			'update_time'	=>	time(),
			'call_num'		=>	self::$callNum,
			'is_invalid'	=>	0
		];

		$info = self::updateTokenCache($token, $updateTokenInfo);
		if ($info['code'] == 0) {
			$updateTokenInfo['token'] = $newTokenInfo['cryptToken'];
			HandleLog()->addLog('u', $updateTokenInfo, '更新了token');
			return ModelReturn(0, '更新TOKEN成功', $updateTokenInfo);
		}
		return $info;
	}

	/**
	 * 更新token信息
	 * @param $token
	 * @param array $updateData
	 * @param bool $isUpdateDb
	 * @return array
	 */
	public static function updateTokenCache($token, $updateData = [], $isUpdateDb=true) {
		$userInfo = self::getUserInfo($token);
		if ($userInfo['code'] != 0) {
			return ModelReturn(1, $userInfo['msg']);
		}

		$userObj = $userInfo['data'];
		$tokenInfo = $userObj['tokenInfo'];
		foreach ($updateData as $key => $value) {
			isset($tokenInfo[$key]) && $tokenInfo[$key] = $value;
		}
		$tokenInfo['update_time'] = time();
		$userObj['tokenInfo'] = $tokenInfo;
		$cacheToken = self::$cachePrefix . $token;
		if (!DB::table('sc_token_cache')->where('token', $token)->first()) {
			return ModelReturn(1, "更新Token缓存信息失败");
		}

		try {
			Cache::put($cacheToken, $userObj, self::$expireTime);
			$isUpdateDb && DB::table('sc_token_cache')->where('token', $token)->update($userObj['tokenInfo']);
			return ModelReturn(0, '更新成功', Cache::get($cacheToken));
		} catch (\Throwable $e) {
			self::LoginOut($token);
			if (config('app.debug')) {
				return ModelReturn(1, $e->getMessage());
			} else {
				return ModelReturn(1, "更新Token缓存信息失败");
			}
		}
	}

	/**
	 * 退出登录
	 * @param $token
	 * @return array
	 */
	public static function LoginOut($token) {
		$cacheToken = self::$cachePrefix . $token;
		Cache::forget($cacheToken);
		DB::table('sc_token_cache')->where('token', $token)->update([
			'is_invalid'	=>	1,
			'update_time'	=>	time()
		]);
		HandleLog()->addLog('d', ['token'=>$token], '退出了系统');
		return ModelReturn(0, '退出登录成功');
	}

	/**
	 * 获取当前用户菜单
	 * @param $token
	 * @return array
	 */
	public static function getUserMenuList($token) {
		self::addMenuItem(['name'  =>  '首页', 'icon'  =>  '&#xe6b8;', 'href'  =>  ''], '');
		self::addMenuItem(['name'  =>  '接口文档', 'icon'  =>  '&#xe812;', 'href'  =>  GetStaticHttpUrl('page/api/api_show.html')], '首页');
		$isAdmin = ScarecrowAuth::isAdmin($token);
		if ($isAdmin) {
			self::addMenuItem(['name'  =>  '系统管理', 'icon'  =>  '&#xe6ae;', 'href'  =>  ''], '');
			self::addMenuItem(['name'  =>  '用户管理', 'icon'  =>  '&#xe6b8;', 'href'  =>  GetStaticHttpUrl('page/user/user_list.html')], '系统管理');
			self::addMenuItem(['name'  =>  '权限管理', 'icon'  =>  '&#xe6e5;', 'href'  =>  GetStaticHttpUrl('page/auth/auth.html')], '系统管理');
			self::addMenuItem(['name'  =>  '项目管理', 'icon'  =>  '&#xe839;', 'href'  =>  GetStaticHttpUrl('page/project/project_manage.html')], '系统管理');
		}

		$userId = ScarecrowAuth::id($token);
		$hasAllProject = DB::table('sc_user_all_project_auth')->where(['user_id'=>$userId, 'write'=>1])->first();
		$hasProject = DB::table('sc_user_project_auth')->where(['user_id'=>$userId, 'write'=>1])->first();
		if ($isAdmin || $hasAllProject ||$hasProject) {
			self::addMenuItem(['name'  =>  '接口管理', 'icon'  =>  '&#xe6ae;', 'href'  =>  ''], '');
			self::addMenuItem(['name'  =>  '编辑分类', 'icon'  =>  '&#xe6cb;', 'href'  =>  GetStaticHttpUrl('page/project/category_manage.html')], '接口管理');
			self::addMenuItem(['name'  =>  '编辑接口', 'icon'  =>  '&#xe74a;', 'href'  =>  GetStaticHttpUrl('page/project/api_manage.html')], '接口管理');
		}
		return ModelReturn(0, '获取成功', self::$userMenu);
	}

	/**
	 * 添加菜单项
	 * @param $item
	 * @param string $parentName
	 * @return bool
	 */
	protected static function addMenuItem($item, $parentName='') {
		if ($parentName == '') {
			self::$userMenu[] = $item;
			return true;
		}

		foreach (self::$userMenu as &$menu) {
			if ($menu['name'] == $parentName) {
				isset($menu['child']) || $menu['child'] = [];
				$menu['child'][] = $item;
				return true;
			}
		}

		return false;
	}
}